package com.twilight.SofaStream;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.StatFs;


public class PlayerService extends Service {

	private MediaPlayer mp = new MediaPlayer();
	private boolean mActive = false, mRemote;
	//Optional id and title to identify this track to other activities
	private RSSItem mItem;
	private NotificationManager nm;
	private static final int PLAYING_ID = 0;
	
	//Callback types
	public final static int PREPARED = 0;
	public final static int UPDATE = 1;
	public final static int BUFFERING = 2;
	public final static int FINISHED = 3;
	public final static int ERROR = 4;
	public final static int COMPLETION = 5;
	public final static int callbackCount = 6;
	private RemoteCallbackList<IPlayerServiceCallback> mCallbacks = new RemoteCallbackList<IPlayerServiceCallback>();
	private String mErrorString = "";

	
    Handler mUpdateHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
				case UPDATE:
					processCallbacks(UPDATE, mp.getCurrentPosition());
					mUpdateHandler.sendMessageDelayed(obtainMessage(UPDATE), 1000);
				default:
	                super.handleMessage(msg);
			}
		}
	};

	private void setActive(boolean active) {
		mActive = active;
		if (active) {
			Notification notification =  new Notification(R.drawable.icon, null, System.currentTimeMillis());
			notification.tickerText = String.format(getResources().getString(R.string.player_playing), mItem.title);
			//notification.flags = Notification.FLAG_ONGOING_EVENT;
			notification.icon = R.drawable.icon;
			PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, EpisodeList.class), 0);
			notification.setLatestEventInfo(this, "SofaStream", String.format(getResources().getString(R.string.player_playing), mItem.title), contentIntent);
			nm.notify(PLAYING_ID, notification);
			processCallbacks(PREPARED, 0);
		} else {
			nm.cancel(PLAYING_ID);			
		}
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
			public void onPrepared(MediaPlayer mp) {
				setActive(true);
			}
		});
		mp.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {
			public void onBufferingUpdate(MediaPlayer mp, int progress) {
				processCallbacks(BUFFERING, progress * mp.getDuration() / 100);
			}			
		});
		mp.setOnErrorListener(new OnErrorListener() {
			public boolean onError(MediaPlayer mp, int what, int extra) {
				processCallbacks(ERROR, what);
				return true;
			}
		});
		mp.setOnCompletionListener(new OnCompletionListener() {
			public void onCompletion(MediaPlayer mp) {
				stopUpdates();
				setActive(false);
				processCallbacks(COMPLETION, 0);
			}
		});
		
	}
	
	private void processCallbacks(int type, int value) {
	    // Broadcast to all clients the new value.
	    final int N = mCallbacks.beginBroadcast();
	    for (int i=0; i<N; i++) {
	        try {
	        	mCallbacks.getBroadcastItem(i).update(type, value);
	        } catch (RemoteException e) {
	            // The RemoteCallbackList will take care of removing
	            // the dead object for us.
	        }
	    }
	    mCallbacks.finishBroadcast();
	}

	@Override
	public void onDestroy() {
		mp.stop();
		mp.release();
        // Unregister all callbacks from all types.
		mCallbacks.kill();
	}

	private void startUpdates() {
		mUpdateHandler.sendEmptyMessage(UPDATE);
	}

	private void stopUpdates() {
		mUpdateHandler.removeMessages(UPDATE);
	}
	
	public void start() {
		mp.start();
		startUpdates();
	}

	public void pause() {
		stopUpdates();
		mp.pause();
	}

	public void stop() {
		stopUpdates();
		mp.stop();
		setActive(false);
	}
	
	public void seekTo(int progress) {
		mp.seekTo(progress);
	}
	
	public int duration() {
		return mp.getDuration();
	}
	
	public int currentPosition() {
		return mp.getCurrentPosition();
	}

	public boolean playing() {
		return mp.isPlaying();
	}
	
	public boolean remotePlay(long id) {
		RSSDB db = new RSSDB(this);
		mItem = db.getArticle(id);
		if (mItem.remotefile == null) {
			mErrorString = getResources().getString(R.string.player_missing_download);
			return false;
		}
		try {
			mp.reset();
			mp.setDataSource(this, Uri.parse(mItem.remotefile.toString()));
			mp.prepareAsync();
			mRemote = true;
			return true;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public boolean localPlay(long id) {
		RSSDB db = new RSSDB(this);
		mItem = db.getArticle(id);
		try {
    		String storageFS = Environment.getExternalStorageDirectory().toString();
    		File path = new File(storageFS + DownloadService.storagePath + mItem.localfile);
			mp.reset();
			mp.setDataSource(path.toString());
			mp.prepare();
			mp.start();
			setActive(true);
			startUpdates();
			mRemote = false;
			return true;
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block	
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}
	
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /**
     * The IRemoteInterface is defined through IDL
     */
    private final IPlayerService.Stub mBinder = new IPlayerService.Stub() {
        public void registerCallback(IPlayerServiceCallback cb) {
            if (cb != null) mCallbacks.register(cb);
        }
        public void unregisterCallback(IPlayerServiceCallback cb) {
            if (cb != null) mCallbacks.unregister(cb);
        }
    	public boolean remoteTrack(long id) {
    		return remotePlay(id);
    	}
    	public boolean localTrack(long id) {
    		return localPlay(id);
    	}
    	public void startTrack() {
    		start();
    	}
    	public void pauseTrack() {
    		pause();
    	}
    	public void stopTrack() {
    		stop();
    	}
    	public void seekTrack(int progress) {
    		seekTo(progress);
    	}
    	public int getCurrentPosition() {
    		return currentPosition();
    	}
    	public int getDuration() {
    		return duration();
    	}
    	public boolean isPlaying() {
    		return playing();
    	}
    	public boolean isActive() {
    		return mActive;
    	}
    	public boolean isRemote() {
    		return mRemote;
    	}
    	public String getTitle() {
    		return mItem.title;
    	}
    	public long getId() {
    		return mItem.id;
    	}
		public String getError() {
			return mErrorString;
		}
    };
}
